package br.ufpb.di.ppgi.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JRExporter;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.JRPdfExporter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import br.com.caelum.vraptor.interceptor.download.Download;
import br.com.caelum.vraptor.interceptor.download.InputStreamDownload;
import br.com.caelum.vraptor.ioc.Component;
import br.ufpb.di.ppgi.apresentacao.SiteConfiguration;

@Component
public class PdfUtil {

	private static final Logger LOGGER = LoggerFactory.getLogger(PdfUtil.class);
	
	private final String jasperDir;
	private final String contextDir;
	private final HttpServletResponse response;
	
	public PdfUtil(SiteConfiguration conf, HttpServletResponse response) {
		this.contextDir = conf.getContextDirPath();
		this.jasperDir = conf.getJasperDirPath(); 
		this.response = response;
	}
	
	public Download downloadPdf(String pdfFile, String finalFilename) {
		try {
			InputStream pdf = new FileInputStream(new File(pdfFile));
			String contentType = "application/pdf";  
			
			return new InputStreamDownload(pdf, contentType, finalFilename);
		} catch (Exception e) {
			LOGGER.error("PDF Exporter error",e);
			throw new RuntimeException(e);
	    } 
	}
	
	public void makePdfFromJasperFile(String jasperFile,Collection<?> dataSource) {
		makePdfFromJasperFile(jasperFile, dataSource,  new HashMap<String, Object>());
	}
	
	public void makePdfFromJasperFile(String jasperFile,Collection<?> dataSource,Map<String,Object> parametros) {
		jasperFile = jasperDir+jasperFile;
		parametros.put("jasperPath", jasperDir);
		parametros.put("contextPath", contextDir);
        try {	        	
            // Fill the report using an empty data source
             JasperPrint print = JasperFillManager.fillReport(jasperFile, parametros, new JRBeanCollectionDataSource(dataSource));
            
            // Create a PDF exporter
            JRExporter exporter = new JRPdfExporter();
            
            // Configure the exporter (set to response output pdf file)
            response.setContentType("application/pdf");
            
            exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, response.getOutputStream());
            exporter.setParameter(JRExporterParameter.JASPER_PRINT, print);
            
            // Export the PDF file
            exporter.exportReport();
            
		} catch (Exception e) {
			LOGGER.error("PDF Exporter error",e);
			throw new RuntimeException(e);
        } 
	}
	
	/**
	 * Cria um PDF a partir da coleção de Beans <tt>dataSource</tt> enviada.
	 * 
	 * dois parametros são injetados por este método o "jasperPath" contendo o caminho
	 * para a paste dos arquivos jasper e o "contextPath" contendo o caminho para a raiz
	 * do aplicativo web. 
	 * @param jasperFile o nome do arquivo .jasper, o diretório onde o .jasper deve estar
	 * 			é definido no properties através do parametro "jasper.dir".
	 * @param dataSource a coleção de beans a ser usada no reporter.
	 * @param fileName o nome do arquivo a ser gerado.
	 * @param doDownload se o arquivo é para download, em caso de <tt>false</tt> o arquivo
	 * 			poderá ser aberto no proprio browser.
	 * @return um {@link Download} a ser enviado como retorno.
	 */
	public Download makePdfFromJasperFile(String jasperFile,Collection<?> dataSource, String fileName, boolean doDownload) {
		return makePdfFromJasperFile(jasperFile, dataSource, fileName, doDownload, new HashMap<String, Object>());
	}
	
	/**
	 * Cria um PDF a partir da coleção de Beans <tt>dataSource</tt> enviada.
	 * @param jasperFile o nome do arquivo .jasper, o diretório onde o .jasper deve estar
	 * 			é definido no properties através do parametro "jasper.dir".
	 * @param dataSource a coleção de beans a ser usada no reporter.
	 * @param fileName o nome do arquivo a ser gerado.
	 * @param doDownload se o arquivo é para download, em caso de <tt>false</tt> o arquivo
	 * 			poderá ser aberto no proprio browser.
	 * @param parametros os parametros a serem passados ao jasper reporter, dois 
	 * 			parametros são injetados por este método o "jasperPath" contendo o caminho
	 * 			para a paste dos arquivos jasper e o "contextPath" contendo o caminho
	 * 			para a raiz do aplicativo web. 
	 * @return um {@link Download} a ser enviado como retorno.
	 */
	public Download makePdfFromJasperFile(String jasperFile,Collection<?> dataSource, String fileName, boolean doDownload, Map<String,Object> parametros) {
		jasperFile = jasperDir+jasperFile;
		parametros.put("jasperPath", jasperDir);
		parametros.put("contextPath", contextDir);
        try {	
        	JasperPrint print;
            // Fill the report using an empty data source
        	if (dataSource == null)
        		print = JasperFillManager.fillReport(jasperFile, parametros, new JREmptyDataSource());
        	else
        		print = JasperFillManager.fillReport(jasperFile, parametros, new JRBeanCollectionDataSource(dataSource));
            
            // Create a PDF exporter
            JRExporter exporter = new JRPdfExporter();

    		ByteArrayOutputStream exported = new ByteArrayOutputStream();
    		
            exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, exported);
            exporter.setParameter(JRExporterParameter.JASPER_PRINT, print);
            
           // Export the PDF file
            exporter.exportReport();
            
            byte[] content = exported.toByteArray();
    		InputStream inputStream = new ByteArrayInputStream(content);
            
            return new InputStreamDownload(inputStream, "application/pdf", fileName,doDownload,content.length);
            
		} catch (Exception e) {
			LOGGER.error("PDF Exporter error",e);
			throw new RuntimeException(e);
        }
		
	}
}